using System;
using System.Diagnostics;

public static class Program {
   public static void Main() {
      const Int32 numElements = 100;
      const Int32 testCount = 10000;
      Stopwatch sw;

      // Declare a 2-dimensional array
      Int32[,] a2Dim = new Int32[numElements, numElements];

      // Declare a 2-dimensional array as a jagged array (a vector of vectors)
      Int32[][] aJagged = new Int32[numElements][];
      for (Int32 x = 0; x < numElements; x++)
         aJagged[x] = new Int32[numElements];


      // 1: Access all elements of the array using the usual, safe technique
      sw = Stopwatch.StartNew();
      for (Int32 test = 0; test < testCount; test++)
         Safe2DimArrayAccess(a2Dim);
      Console.WriteLine("{0}: Safe2DimArrayAccess", sw.Elapsed);

      // 2: Access all elements of the array using the jagged array technique
      sw = Stopwatch.StartNew();
      for (Int32 test = 0; test < testCount; test++)
         SafeJaggedArrayAccess(aJagged);
      Console.WriteLine("{0}: SafeJaggedArrayAccess", sw.Elapsed);

      // 3: Access all elements of the array using the unsafe technique
      sw = Stopwatch.StartNew();
      for (Int32 test = 0; test < testCount; test++)
         Unsafe2DimArrayAccess(a2Dim);
      Console.WriteLine("{0}: Unsafe2DimArrayAccess", sw.Elapsed);
   }

   private static void Safe2DimArrayAccess(Int32[,] a) {
      for (Int32 x = 0; x < a.GetLength(0); x++) {
         for (Int32 y = 0; y < a.GetLength(1); y++) {
            Int32 element = a[x, y];
         }
      }
   }

   private static void SafeJaggedArrayAccess(Int32[][] a) {
      for (Int32 x = 0; x < a.GetLength(0); x++) {
         for (Int32 y = 0; y < a[x].GetLength(0); y++) {
            Int32 element = a[x][y];
         }
      }
   }
   
   private static unsafe void Unsafe2DimArrayAccess(Int32[,] a) {
      Int32 dim0LowIndex  = 0;   // a.GetLowerBound(0);
      Int32 dim0HighIndex = a.GetUpperBound(0);

      Int32 dim1LowIndex  = 0;   // a.GetLowerBound(1);
      Int32 dim1HighIndex = a.GetUpperBound(1);

      Int32 dim1Elements = dim1HighIndex - dim1LowIndex + 1;

      fixed (Int32* pi = &a[0, 0]) {
         for (Int32 x = dim0LowIndex; x <= dim0HighIndex; x++) {
            Int32 baseOfDim = x * dim1Elements;
            for (Int32 y = dim1LowIndex; y <= dim1HighIndex; y++) {
               Int32 element = pi[baseOfDim + y];
               Console.WriteLine("{0}, {1} = {2}", x, y, element);
            }
         }
      }
   }
}
